PropertyUtility.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using UnityEditor;
  2. using System.Reflection;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. namespace ExternPropertyAttributes.Editor
  8. {
  9. public static class PropertyUtility
  10. {
  11. public static T GetAttribute<T>(SerializedProperty property) where T : class
  12. {
  13. T[] attributes = GetAttributes<T>(property);
  14. return (attributes.Length > 0) ? attributes[0] : null;
  15. }
  16. public static T[] GetAttributes<T>(SerializedProperty property) where T : class
  17. {
  18. FieldInfo fieldInfo = ReflectionUtility.GetField(GetTargetObjectWithProperty(property), property.name);
  19. if (fieldInfo == null)
  20. {
  21. return new T[] { };
  22. }
  23. return (T[])fieldInfo.GetCustomAttributes(typeof(T), true);
  24. }
  25. public static GUIContent GetLabel(SerializedProperty property)
  26. {
  27. LabelAttribute labelAttribute = GetAttribute<LabelAttribute>(property);
  28. string labelText = (labelAttribute == null)
  29. ? property.displayName
  30. : labelAttribute.Label;
  31. GUIContent label = new GUIContent(labelText);
  32. return label;
  33. }
  34. public static void CallOnValueChangedCallbacks(SerializedProperty property)
  35. {
  36. OnValueChangedAttribute[] onValueChangedAttributes = GetAttributes<OnValueChangedAttribute>(property);
  37. if (onValueChangedAttributes.Length == 0)
  38. {
  39. return;
  40. }
  41. object target = GetTargetObjectWithProperty(property);
  42. property.serializedObject.ApplyModifiedProperties(); // We must apply modifications so that the new value is updated in the serialized object
  43. foreach (var onValueChangedAttribute in onValueChangedAttributes)
  44. {
  45. MethodInfo callbackMethod = ReflectionUtility.GetMethod(target, onValueChangedAttribute.CallbackName);
  46. if (callbackMethod != null &&
  47. callbackMethod.ReturnType == typeof(void) &&
  48. callbackMethod.GetParameters().Length == 0)
  49. {
  50. callbackMethod.Invoke(target, new object[] { });
  51. }
  52. else
  53. {
  54. string warning = string.Format(
  55. "{0} can invoke only methods with 'void' return type and 0 parameters",
  56. onValueChangedAttribute.GetType().Name);
  57. Debug.LogWarning(warning, property.serializedObject.targetObject);
  58. }
  59. }
  60. }
  61. public static bool IsEnabled(SerializedProperty property)
  62. {
  63. EnableIfAttributeBase enableIfAttribute = GetAttribute<EnableIfAttributeBase>(property);
  64. if (enableIfAttribute == null)
  65. {
  66. return true;
  67. }
  68. object target = GetTargetObjectWithProperty(property);
  69. List<bool> conditionValues = GetConditionValues(target, enableIfAttribute.Conditions);
  70. if (conditionValues.Count > 0)
  71. {
  72. bool enabled = GetConditionsFlag(conditionValues, enableIfAttribute.ConditionOperator, enableIfAttribute.Inverted);
  73. return enabled;
  74. }
  75. else
  76. {
  77. string message = enableIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
  78. Debug.LogWarning(message, property.serializedObject.targetObject);
  79. return false;
  80. }
  81. }
  82. public static bool IsVisible(SerializedProperty property)
  83. {
  84. ShowIfAttributeBase showIfAttribute = GetAttribute<ShowIfAttributeBase>(property);
  85. if (showIfAttribute == null)
  86. {
  87. return true;
  88. }
  89. object target = GetTargetObjectWithProperty(property);
  90. List<bool> conditionValues = GetConditionValues(target, showIfAttribute.Conditions);
  91. if (conditionValues.Count > 0)
  92. {
  93. bool enabled = GetConditionsFlag(conditionValues, showIfAttribute.ConditionOperator, showIfAttribute.Inverted);
  94. return enabled;
  95. }
  96. else
  97. {
  98. string message = showIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
  99. Debug.LogWarning(message, property.serializedObject.targetObject);
  100. return false;
  101. }
  102. }
  103. internal static List<bool> GetConditionValues(object target, string[] conditions)
  104. {
  105. List<bool> conditionValues = new List<bool>();
  106. foreach (var condition in conditions)
  107. {
  108. FieldInfo conditionField = ReflectionUtility.GetField(target, condition);
  109. if (conditionField != null &&
  110. conditionField.FieldType == typeof(bool))
  111. {
  112. conditionValues.Add((bool)conditionField.GetValue(target));
  113. }
  114. PropertyInfo conditionProperty = ReflectionUtility.GetProperty(target, condition);
  115. if (conditionProperty != null &&
  116. conditionProperty.PropertyType == typeof(bool))
  117. {
  118. conditionValues.Add((bool)conditionProperty.GetValue(target));
  119. }
  120. MethodInfo conditionMethod = ReflectionUtility.GetMethod(target, condition);
  121. if (conditionMethod != null &&
  122. conditionMethod.ReturnType == typeof(bool) &&
  123. conditionMethod.GetParameters().Length == 0)
  124. {
  125. conditionValues.Add((bool)conditionMethod.Invoke(target, null));
  126. }
  127. }
  128. return conditionValues;
  129. }
  130. internal static bool GetConditionsFlag(List<bool> conditionValues, EConditionOperator conditionOperator, bool invert)
  131. {
  132. bool flag;
  133. if (conditionOperator == EConditionOperator.And)
  134. {
  135. flag = true;
  136. foreach (var value in conditionValues)
  137. {
  138. flag = flag && value;
  139. }
  140. }
  141. else
  142. {
  143. flag = false;
  144. foreach (var value in conditionValues)
  145. {
  146. flag = flag || value;
  147. }
  148. }
  149. if (invert)
  150. {
  151. flag = !flag;
  152. }
  153. return flag;
  154. }
  155. public static Type GetPropertyType(SerializedProperty property)
  156. {
  157. Type parentType = GetTargetObjectWithProperty(property).GetType();
  158. FieldInfo fieldInfo = parentType.GetField(property.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  159. return fieldInfo.FieldType;
  160. }
  161. /// <summary>
  162. /// Gets the object the property represents.
  163. /// </summary>
  164. /// <param name="property"></param>
  165. /// <returns></returns>
  166. public static object GetTargetObjectOfProperty(SerializedProperty property)
  167. {
  168. if (property == null)
  169. {
  170. return null;
  171. }
  172. string path = property.propertyPath.Replace(".Array.data[", "[");
  173. object obj = property.serializedObject.targetObject;
  174. string[] elements = path.Split('.');
  175. foreach (var element in elements)
  176. {
  177. if (element.Contains("["))
  178. {
  179. string elementName = element.Substring(0, element.IndexOf("["));
  180. int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
  181. obj = GetValue_Imp(obj, elementName, index);
  182. }
  183. else
  184. {
  185. obj = GetValue_Imp(obj, element);
  186. }
  187. }
  188. return obj;
  189. }
  190. /// <summary>
  191. /// Gets the object that the property is a member of
  192. /// </summary>
  193. /// <param name="property"></param>
  194. /// <returns></returns>
  195. public static object GetTargetObjectWithProperty(SerializedProperty property)
  196. {
  197. string path = property.propertyPath.Replace(".Array.data[", "[");
  198. object obj = property.serializedObject.targetObject;
  199. string[] elements = path.Split('.');
  200. for (int i = 0; i < elements.Length - 1; i++)
  201. {
  202. string element = elements[i];
  203. if (element.Contains("["))
  204. {
  205. string elementName = element.Substring(0, element.IndexOf("["));
  206. int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
  207. obj = GetValue_Imp(obj, elementName, index);
  208. }
  209. else
  210. {
  211. obj = GetValue_Imp(obj, element);
  212. }
  213. }
  214. return obj;
  215. }
  216. private static object GetValue_Imp(object source, string name)
  217. {
  218. if (source == null)
  219. {
  220. return null;
  221. }
  222. Type type = source.GetType();
  223. while (type != null)
  224. {
  225. FieldInfo field = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
  226. if (field != null)
  227. {
  228. return field.GetValue(source);
  229. }
  230. PropertyInfo property = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
  231. if (property != null)
  232. {
  233. return property.GetValue(source, null);
  234. }
  235. type = type.BaseType;
  236. }
  237. return null;
  238. }
  239. private static object GetValue_Imp(object source, string name, int index)
  240. {
  241. IEnumerable enumerable = GetValue_Imp(source, name) as IEnumerable;
  242. if (enumerable == null)
  243. {
  244. return null;
  245. }
  246. IEnumerator enumerator = enumerable.GetEnumerator();
  247. for (int i = 0; i <= index; i++)
  248. {
  249. if (!enumerator.MoveNext())
  250. {
  251. return null;
  252. }
  253. }
  254. return enumerator.Current;
  255. }
  256. }
  257. }